<template>
  <div :style="field.formGroupStyle"
       :class="[field.fields === undefined ? 'df-form-group' : 'df-complex-form-group', {[schema.errorFieldClass]: error && error.rule}, field.formGroupClass]">
    <label-field
      :schema="schema"
      :field="field"
      :model="model"
      :formModel="formModel"></label-field>
    <div :style="field.inputWrapperStyle" :class="[field.fields === undefined ? 'df-input-wrapper' : 'df-complex-field-wrapper', field.inputWrapperClass]">
      <template v-if="field.fields === undefined">
        <div :class="[schema.commonInputGroupClass, {'df-input-loading': isLoading}]" v-if="field.addon">
          <span :class="schema.commonInputGroupAddonClass" v-if="field.addonOnLeft">{{field.addon}}</span>
          <div :is="inputComponent"
               :index="index"
               :value="model[field.name]"
               :field="field"
               :model="model"
               :form-group="context"
               :schema="schema"
               :form-model="formModel"
               :form-submitting="formSubmitting"
               @validate="onValidate"
               @pending="onPending"
               @loading="onLoading"
               @field-destroyed="onFieldDestroyed"></div>
          <span :class="schema.commonInputGroupAddonClass" v-if="!field.addonOnLeft">{{field.addon}}</span>
        </div>
        <div v-else :is="inputComponent" :class="{'df-input-loading': isLoading}"
             :index="index"
             :value="model[field.name]"
             :field="field"
             :model="model"
             :schema="schema"
             :form-model="formModel"
             :form-submitting="formSubmitting"
             @validate="onValidate"
             @pending="onPending"
             @loading="onLoading"
             @field-destroyed="onFieldDestroyed"></div>
      </template>
      <template v-else>
        <template v-if="field.repeatable">
          <template v-for="(m, idx) in model[field.name]">
            <div :key="m" class="df-repeat-item-wrapper" :style="field.repeatItemWrapperStyle" :class="field.repeatItemWrapperClass">
              <template v-for="(subField, idx01) in field.fields">
                <dynamic-form-form-group
                  :key="m"
                  :index="index"
                  :locale="locale"
                  :field="subField"
                  :model="m"
                  :schema="schema"
                  :formModel="formModel"
                  :parent="context"
                  :form-submitting="formSubmitting"
                  @loading="onArrayLoading"
                  @validate="onArrayValidate"
                  @pending="onArrayPending"
                  @field-destroyed="onFieldDestroyed"></dynamic-form-form-group>
              </template>
              <div class="df-button-wrapper" :style="field.repeatActionsWrapperStyle" :class="field.repeatActionsWrapperClass">
                <button type="button" :style="field.repeatActionButtonStyle" :class="[schema.commonButtonClass, field.repeatActionButtonClass]"
                        :disabled="idx === 0" @click.prevent="repeatUp(m)">
                  {{locale.up}}
                </button>
                <button type="button" :style="field.repeatActionButtonStyle" :class="[schema.commonButtonClass, field.repeatActionButtonClass]"
                        :disabled="idx === model[field.name].length - 1" @click.prevent="repeatDown(m)">
                  {{locale.down}}
                </button>
                <button type="button" :style="field.repeatActionButtonStyle" :class="[schema.commonButtonClass, field.repeatActionButtonClass]"
                        :disabled="repeatMaxLength > 0 && idx > repeatMaxLength" @click.prevent="repeatAdd(m)">
                  {{locale.add}}
                </button>
                <button type="button" :style="field.repeatActionButtonStyle" :class="[schema.commonButtonClass, field.repeatActionButtonClass]"
                        :disabled="idx < repeatMinLength" @click.prevent="repeatRemove(m)">
                  {{locale.remove}}
                </button>
              </div>
            </div>
          </template>
          <div class="df-button-wrapper" :style="field.repeatActionsWrapperStyle" :class="[schema.commonButtonClass, field.repeatActionsWrapperClass]">
            <button type="button" v-if="!model[field.name] || model[field.name].length === 0" @click.prevent="repeatAdd()">
              {{locale.add}}
            </button>
          </div>
        </template>
        <template v-else v-for="(subField, idx) in field.fields">
          <dynamic-form-form-group
            :key="idx"
            :index="index"
            :locale="locale"
            :field="subField"
            :model="model[field.name]"
            :schema="schema"
            :formModel="formModel"
            :parent="context"
            :form-submitting="formSubmitting"
            @loading="onObjectLoading"
            @validate="onObjectValidate"
            @pending="onObjectPending"
            @field-destroyed="onFieldDestroyed"></dynamic-form-form-group>
        </template>
      </template>
      <help-field
        :schema="schema"
        :field="field"
        :model="model"
        :formModel="formModel"
        :error="error"
        :locale="locale"></help-field>
      <p class="df-description" v-if="field.description" v-html="field.description"></p>
    </div>
  </div>
</template>

<script>
  import _ from 'lodash'
  import Vue from 'vue'
  import InputField from './InputField.vue'
  import LabelField from './LabelField.vue'
  import HelpField from './HelpField.vue'

  let _objectModelKeyId = 0

  function getObjectModelKeyId () {
    return ++_objectModelKeyId
  }

  export default {
    name: 'DynamicFormFormGroup',
    components: { LabelField, HelpField, InputField },
    props: {
      index: Number,
      locale: Object,
      schema: {
        type: Object,
        default () {
          return {}
        }
      },
      field: {
        type: Object,
        default () {
          return {}
        }
      },
      model: {
        type: Object,
        required: true
      },
      formModel: {
        type: Object,
        required: true
      },
      formSubmitting: {
        type: Boolean,
        default: false
      },
      parent: {}
    },
    computed: {
      repeatMinLength () {
        if (_.isNil(this.field.repeatMinLength)) {
          return 0
        }
        if (_.isFunction(this.field.repeatMinLength)) {
          return this.field.repeatMinLength(this.model, this.formModel, this.field) || 0
        }
        return this.field.repeatMinLength || 0
      },
      repeatMaxLength () {
        if (_.isNil(this.field.repeatMaxLength)) {
          return null
        }
        if (_.isFunction(this.field.repeatMaxLength)) {
          return this.field.repeatMaxLength(this.model, this.formModel, this.field) || null
        }
        return this.field.repeatMaxLength || null
      },
      repeatDefaultModel () {
        if (_.isNil(this.field.repeatDefaultModel)) {
          return {}
        }
        if (_.isFunction(this.field.repeatDefaultModel)) {
          return this.field.repeatDefaultModel(this.model, this.formModel, this.field) || {}
        }
        return this.field.repeatDefaultModel || {}
      }
    },
    data () {
      return {
        isLoading: false,
        error: null,
        repeatErrors: {},
        inputComponent: InputField,
        // 仅为了让Vue监听model对象
        curModel: this.model,
        context: this
      }
    },
    created () {
      if (this.field.fields) {
        if (this.field.repeatable) {
          let fieldModel = this.model[this.field.name]
          if (!fieldModel || !_.isArray(fieldModel)) {
            Vue.set(this.model, this.field.name, [])
          }
          if (this.repeatMinLength > 0 && this.model[this.field.name].length < this.repeatMinLength) {
            while (this.model[this.field.name].length < this.repeatMinLength) {
              this.model[this.field.name].push(this.getNewRepeatModel())
            }
          }
        } else {
          if (this.model[this.field.name] === undefined) {
            this.model[this.field.name] = {}
          }
          this.model[this.field.name].__key = getObjectModelKeyId()
        }
      }
    },
    methods: {
      getNewRepeatModel () {
        let obj = _.cloneDeep(this.repeatDefaultModel)
        obj.__key = getObjectModelKeyId()
        return obj
      },
      repeatUp (model) {
        let idx = _.indexOf(this.model[this.field.name], model)
        if (idx > 0) {
          this.model[this.field.name].splice(idx, 1)
          this.model[this.field.name].splice(idx - 1, 0, model)
        }
      },
      repeatDown (model) {
        let idx = _.indexOf(this.model[this.field.name], model)
        if (idx < this.model[this.field.name].length - 1) {
          this.model[this.field.name].splice(idx, 1)
          this.model[this.field.name].splice(idx + 1, 0, model)
        }
      },
      repeatAdd (model) {
        let idx = this.model[this.field.name].length
        if (model) {
          idx = _.indexOf(this.model[this.field.name], model) + 1
        }
        this.model[this.field.name].splice(idx, 0, this.getNewRepeatModel())
      },
      repeatRemove (model) {
        let idx = _.indexOf(this.model[this.field.name], model)
        this.model[this.field.name].splice(idx, 1)
      },
      onLoading (params) {
        this.isLoading = params.isLoading
        this.$emit('loading', params)
      },
      onObjectLoading (params) {
        this.$emit('loading', params)
      },
      onArrayLoading (params) {
        this.$emit('loading', params)
      },
      onValidate (params) {
        this.error = params
        this.$emit('validate', params)
      },
      onObjectValidate (params) {
        this.$emit('validate', params)
      },
      onArrayValidate (params) {
        this.$emit('validate', params)
      },
      onPending (params) {
        this.$emit('pending', params)
      },
      onObjectPending (params) {
        this.$emit('pending', params)
      },
      onArrayPending (params) {
        this.$emit('pending', params)
      },
      onFieldDestroyed (params) {
        this.$emit('field-destroyed', params)
      }
    }
  }
</script>
